# Copyright 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: tu@tulrich.com (Thatcher Ulrich)

"""Code to handle measurement uploads.
"""

import base64
import datetime
import os
from django.utils import simplejson
from google.appengine.ext import db
from google.appengine.ext.webapp import template
import analysis


class Report(db.Expando):
  #dedupe_hash = db.StringProperty()
  ip = db.StringProperty()
  timestamp = db.DateTimeProperty(auto_now_add=True)


def validname(name):
  """Return true if we can use this name as a key in our Report data model.

  TODO more validation.
  """
  if (name.find(" ") != -1 or
      name.startswith("_")):
    return False
  return True


def to_float_value(val):
  # TODO: if it's a string, make it ""
  # TODO: if it's a NaN, make it "" or "NaN" or something
  return float(val)
  

def parse_report(r, userstats, body):
  """
  """
  userstats["metric"] = {}
  report = simplejson.loads(body)
  if not report.has_key("reporter") or not report.has_key("metric"):
    # Missing required parts.
    return False

  reporter = report["reporter"]
  for k in reporter:
    if not validname(k):
      return False
    setattr(r, "reporter_" + k, reporter[k])

  metric = report["metric"]
  for k in metric:
    if not validname(k):
      return False
    value = to_float_value(metric[k])
    setattr(r, "metric_" + k, value)
    userstats["metric"][k] = value

  userstats["tags"] = analysis.get_tags(report)

  return True


def compute_dedupe_hash(req):
  """Generate a random string, to be (possibly) used to dedupe multiple
  reports from the same client over a limited amount of time.
  """
  return base64.b32encode(os.urandom(10))


def handler(app):
  """Store the measurements supplied in JSON format in the request body.
  """
  r = Report()

  # For privacy reasons let's not store the IP address of uploaders.
  # Later it may be desirable to log IP to prevent spam/abuse, but
  # it's a tricky problem to protect the info properly, so defer until
  # later.
  # r.ip = str(app.request.remote_addr)
  r.ip = ""
  if app.request.cookies.has_key("dedupe_hash"):
    r.dedupe_hash = app.request.cookies["dedupe_hash"]
  else:
    dedupe_hash = compute_dedupe_hash(app.request)
    # 604800 seconds == 7 days
    app.response.headers.add_header(
      "Set-Cookie",
      "dedupe_hash=%s; Max-Age=604800; path=/;" % dedupe_hash)
    r.dedupe_hash = dedupe_hash

  userstats = {}
  if parse_report(r, userstats, app.request.body):
    db.put(r)

    #tags = analysis.get_tags(r)
    #app.response.out.write(analysis.dump_tagsets_for_tags(tags, userstats))

    app.response.out.write("OK")
    #template_values = {}
    #path = os.path.join(os.path.dirname(__file__), "upload.html")
    #app.response.out.write(template.render(path, template_values))

  else:
    app.response.error(500)
    app.response.out.write("error parsing upload\n")
    app.response.out.write(app.request.body)

